// $Id: housekeeping.c 484 2014-05-01 00:58:30Z alan.watson.f $

#define _POSIX_C_SOURCE 200112L

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/statfs.h>

#include "oaxaca-config.h"
#include "oaxaca.h"

////////////////////////////////////////////////////////////////////////////////

int
oaxaca_housekeeping_initialized(void)
{
  return oaxaca_shm->housekeeping.initialized;
}

double
oaxaca_housekeeping_cpu_usage(void)
{
  return oaxaca_shm->housekeeping.cpu_usage;
}

double
oaxaca_housekeeping_disk_usage(void)
{
  return oaxaca_shm->housekeeping.disk_usage;
}

////////////////////////////////////////////////////////////////////////////////

static const int number_of_cpus = 2;

static void
update_cpu_usage(void)
{
  double up;
  double idle;
  static double last_up;
  static double last_idle;

  FILE *fp = fopen("/proc/uptime", "r");
  if (fp == NULL || fscanf(fp, "%lf %lf", &up, &idle) != 2)
    oaxaca_error("unable to determine the CPU usage.");
  fclose(fp);

  double usage = 1 - (idle - last_idle) / (up - last_up) / number_of_cpus;
  if (usage < 0.0)
    usage = 0.0;
  else if (usage > 100.0)
    usage = 100.0;

  oaxaca_shm->housekeeping.cpu_usage = usage;

  last_idle = idle;
  last_up = up;
}

static void
update_disk_usage(void)
{
  struct statfs buf;
  if (statfs(".", &buf) == -1)
    oaxaca_error("unable to determine the disk usage.");

  double usage = 1.0 - (double) buf.f_bavail / (double) buf.f_blocks;
  if (usage < 0.0)
    usage = 0.0;
  else if (usage > 100.0)
    usage = 100.0;

  oaxaca_shm->housekeeping.disk_usage = usage;
}

static void
update_telescope_position(void)
{
  FILE *fp = fopen("../telescope/telescope.txt", "r");
  if (fp == NULL)
    return;

  double alpha, delta, ha, zd;
  if (fscanf(fp, "%*[^,],%lf,%lf,%lf,%lf", &alpha, &delta, &ha, &zd) != 4)
    oaxaca_info("bad telescope.txt file.");

  oaxaca_shm->telescope.alpha = alpha;
  oaxaca_shm->telescope.delta = delta;
  oaxaca_shm->telescope.ha    = ha;
  oaxaca_shm->telescope.zd    = zd;

  fclose(fp);
}

static void
update(void)
{
  update_cpu_usage();
  update_disk_usage();
  update_telescope_position();
}

////////////////////////////////////////////////////////////////////////////////

static void
atexitcallee(void)
{
  if (oaxaca_shm != NULL)
    oaxaca_shm->housekeeping.initialized = 0;
}

void
oaxaca_housekeeping_main(void)
{
  int interval = 3;

  oaxaca_common_main("housekeeping");
  atexit(atexitcallee);
  
  oaxaca_shm->housekeeping.initialized = 0;
  update();
  oaxaca_sleep(interval);
  update();
  oaxaca_shm->housekeeping.initialized = 1;
  oaxaca_info("starting loop.");
  for (;;) {
    oaxaca_sleep(interval);
    update();
  }
  
  oaxaca_error("loop terminated.");
}

////////////////////////////////////////////////////////////////////////////////